﻿using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Linq;

namespace Cheetah_Fast_Banking_App
{
    public class Account
    {
        #region Private Variables
        private string _guid;
        private string _accountName;
        private bool _isAdmin;
        private string _salt;
        private string _passwordHash;
        #endregion // Private Variables

        #region Properties
        public ObservableCollection<Transaction> Transactions { get; set; }
        public ObservableCollection<BillPay> BillPays { get; set; }

        /// <summary>
        /// Unique Identifier for account
        /// </summary>
        public string Guid
        {
            get { return _guid; }
            set { _guid = value; }
        }

        public string AccountName
        {
            get { return _accountName; }
            set { _accountName = value; }
        }

        public bool IsAdmin
        {
            get { return _isAdmin; }
            set { _isAdmin = value; }
        }

        public string Salt
        {
            get { return _salt; }
            set { _salt = value; }
        }

        public string PasswordHash
        {
            get { return _passwordHash; }
            set { _passwordHash = value; }
        }
        #endregion // Properties

        #region Constructors
        /// <summary>
        /// Default Constructor
        /// </summary>
        public Account()
        {
            Transactions = new ObservableCollection<Transaction>();
            BillPays = new ObservableCollection<BillPay>();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="guid">Unique ID for account</param>
        public Account(string guid) : this()
        {
            _guid = guid;
        }
        #endregion // Constructors

        #region Methods
        #region Transaction
        /// <summary>
        /// Save a new Transaction to the current account
        /// </summary>
        /// <param name="transaction">Transaction to be saved</param>
        public void SaveNewTransaction(Transaction transaction)
        {
            string filePath = DataSourceSingleton.GetInstance().XmlFile;
            XDocument doc = XDocument.Load(filePath);
            XElement newElement;
            if (!transaction.BillId.HasValue)
            {
                newElement = new XElement("transaction",
                                            new XAttribute("id", transaction.ID),
                                            new XAttribute("date", transaction.Date.ToString(@"MM/dd/yyyy")),
                                            new XAttribute("description", transaction.Description),
                                            new XAttribute("amount", transaction.Amount));
            }
            else
            {
                newElement = new XElement("transaction",
                                            new XAttribute("id", transaction.ID),
                                            new XAttribute("date", transaction.Date.ToString(@"MM/dd/yyyy")),
                                            new XAttribute("description", transaction.Description),
                                            new XAttribute("amount", transaction.Amount),
                                            new XAttribute("billid", transaction.BillId.Value.ToString()));
            }
            XElement accountElement = (from e in doc.Descendants("account")
                                       where e.Attribute("name").Value == _accountName
                                       select e).Single();
            accountElement.Descendants("transactions").Last().Add(newElement);
            doc.Save(filePath);
            Transactions.Add(transaction);
            SortAndRecalculateTransactions();
        }

        /// <summary>
        /// Deletes a Transaction from the current account
        /// </summary>
        /// <param name="transaction">Transaction to be deleted</param>
        public void DeleteTransaction(Transaction transaction)
        {
            string filePath = DataSourceSingleton.GetInstance().XmlFile;
            XDocument doc = XDocument.Load(filePath);
            XElement transactionElement = (from t in doc.Descendants("transaction")
                                           where t.Attribute("id").Value == transaction.ID.ToString()
                                           select t).Single();
            transactionElement.Remove();
            doc.Save(filePath);
            Transactions.Remove(transaction);
            SortAndRecalculateTransactions();
        }

        public void ModifyTransaction(Transaction transaction)
        {
            string filePath = DataSourceSingleton.GetInstance().XmlFile;
            XDocument doc = XDocument.Load(filePath);
            XElement transactionElement = (from t in doc.Descendants("transaction")
                                           where t.Attribute("id").Value == transaction.ID.ToString()
                                           select t).Single();
            transactionElement.Attribute("date").Value = transaction.Date.ToString(@"MM/dd/yyyy");
            transactionElement.Attribute("description").Value = transaction.Description;
            transactionElement.Attribute("amount").Value = transaction.Amount.ToString();
            doc.Save(filePath);

            // force update
            SortAndRecalculateTransactions();
        }

        private void SortAndRecalculateTransactions()
        {
            Transactions.Sort(new TransactionComparer());
            decimal previousBalance = 0;
            foreach (Transaction t in Transactions)
            {
                t.SetCurrentBalance(previousBalance);
                previousBalance = t.CurrentBalance;
            }
            Transactions.Refresh();
        }
        #endregion

        #region BillPay
        /// <summary>
        /// Save a new Bill Pay to the current account
        /// </summary>
        /// <param name="billpay">BillPay to be saved</param>
        public void SaveNewBillPay(BillPay billpay)
        {
            string filePath = DataSourceSingleton.GetInstance().XmlFile;
            XDocument doc = XDocument.Load(filePath);
            XElement newElement;
            if (billpay.LastDate.HasValue)
            {
                newElement = new XElement("billpay",
                                                new XAttribute("id", billpay.ID),
                                                new XAttribute("description", billpay.Description),
                                                new XAttribute("first", billpay.FirstDate.ToString(@"MM/dd/yyyy")),
                                                new XAttribute("last", billpay.LastDate.Value.ToString(@"MM/dd/yyyy")),
                                                new XAttribute("interval", billpay.Interval),
                                                new XAttribute("active", billpay.Active),
                                                new XAttribute("amount", billpay.Amount));
            }
            else
            {
                newElement = new XElement("billpay",
                                                new XAttribute("id", billpay.ID),
                                                new XAttribute("description", billpay.Description),
                                                new XAttribute("first", billpay.FirstDate.ToString(@"MM/dd/yyyy")),
                                                new XAttribute("interval", billpay.Interval.ToString()),
                                                new XAttribute("active", billpay.Active),
                                                new XAttribute("amount", billpay.Amount));
            }
            XElement accountElement = (from e in doc.Descendants("account")
                                       where e.Attribute("name").Value == _accountName
                                       select e).Single();
            accountElement.Descendants("billpays").Last().Add(newElement);
            doc.Save(filePath);
            BillPays.Add(billpay);
        }

        /// <summary>
        /// Deletes a Bill Pay from the current account
        /// </summary>
        /// <param name="billpay">Bill Pay to be deleted</param>
        public void DeleteBillPay(BillPay billpay)
        {
            string filePath = DataSourceSingleton.GetInstance().XmlFile;
            XDocument doc = XDocument.Load(filePath);
            XElement transactionElement = (from t in doc.Descendants("billpay")
                                           where t.Attribute("id").Value == billpay.ID.ToString()
                                           select t).Single();
            transactionElement.Remove();
            doc.Save(filePath);
            BillPays.Remove(billpay);
        }

        public void ModifyBillPay(BillPay billpay)
        {
            string filePath = DataSourceSingleton.GetInstance().XmlFile;
            XDocument doc = XDocument.Load(filePath);
            XElement transactionElement = (from t in doc.Descendants("billpay")
                                           where t.Attribute("id").Value == billpay.ID.ToString()
                                           select t).Single();
            transactionElement.Attribute("description").Value = billpay.Description;
            transactionElement.Attribute("first").Value = billpay.FirstDate.ToString(@"MM/dd/yyyy");
            EditLastDate(billpay, transactionElement);
            transactionElement.Attribute("interval").Value = billpay.Interval.ToString();
            transactionElement.Attribute("active").Value = billpay.Active.ToString();
            transactionElement.Attribute("amount").Value = billpay.Amount.ToString();
            doc.Save(filePath);

            // force update
            BillPays.Refresh();
        }

        private void EditLastDate(BillPay billpay, XElement transactionElement)
        {
            bool hadLast = transactionElement.Attribute("last") != null;
            bool hasLast = billpay.LastDate.HasValue;
            if (hadLast && hasLast)
                transactionElement.Attribute("last").Value = billpay.LastDate.Value.ToString(@"MM/dd/yyyy");
            else if (hadLast && !hasLast)
                transactionElement.Attribute("last").Remove();
            else if (!hadLast && hasLast)
            {
                XAttribute lastAttribute = new XAttribute("last", billpay.LastDate.Value.ToString(@"MM/dd/yyyy"));
                XAttribute intervalAttribute = transactionElement.Attribute("interval");
                XAttribute activeAttribute = transactionElement.Attribute("active");
                XAttribute amountAttribute = transactionElement.Attribute("amount");
                transactionElement.Attribute("interval").Remove();
                transactionElement.Attribute("active").Remove();
                transactionElement.Attribute("amount").Remove();
                transactionElement.Add(lastAttribute);
                transactionElement.Add(intervalAttribute);
                transactionElement.Add(activeAttribute);
                transactionElement.Add(amountAttribute);
            }
        } 
        #endregion
        #endregion // Methods
    }
}
